<?php
class mcz_Object implements Iterator
{
	const CONSTRAINT_UNIQUE = 23000;
	private $errors = array();
	public function __construct($values = null)
	{
		foreach($this->fields as $k => $v)
		{
			if(isset($v['default']))
			{
				$this->setValue($k, $v['default']);
			}
		}
		if(is_array($values))
		{
			foreach($values as $key => $value)
			{
				$this->setValue($key, $value);
			}
		}
	}

	public function rewind()
	{
		reset($this->fields);
    }

	public function current()
	{
		$field = current($this->fields);
		if(!isset($field['value']))
		{
			$field['value'] = null;
		}
		return $field['value'];
    }

    public function key()
	{
		$var = key($this->fields);
		return $var;
    }

    public function next()
	{
		$field = next($this->fields);
		if(!isset($field['value']))
		{
			$field['value'] = null;
		}
		return $field['value'];
    }

    public function valid()
	{
		if(!is_null($this->key()))
		{
			return true;
		}
		return false;
    }

	private function setValue($key, $value)
	{
		switch($this->fields[$key]['cast'])
		{
			case 'int':
			case 'integer':
				$value = (int)$value;
				break;
			case 'bool':
			case 'boolean':
				$value = (bool)$value;
			default:
				$value = $value;
				break;
		}
		if(!empty($this->fields[$key]['modifiers']))
		{
			foreach($this->fields[$key]['modifiers'] as $modifier)
			{
				$value = $this->{$modifier.'Modifier'}($value);
			}
		}
		$this->fields[$key]['value'] = $value;
	}

	public function __set($key, $value)
	{
		if(isset($this->fields[$key]))
		{
			$this->setValue($key, $value);
		}
	}

	public function __get($key)
	{
		if(isset($this->fields[$key]['value']))
		{
			return $this->fields[$key]['value'];
		}
	}

	public function save()
	{
		if(method_exists($this, 'preSave'))
		{
			$this->preSave();
		}
		if($this->_validates())
		{
			try
			{
				if(empty($this->fields['id']['value']))
				{
					$this->insert();
				}
				else
				{
					$this->update();
				}
				if(method_exists($this, 'postSave'))
				{
					$this->postSave();
				}
			}
			catch(Exception $e)
			{
				switch($e->getCode())
				{
					case '23000':
						throw new Exception('Validation error in ' . get_class($this)
								    . ': unique constraint.',self::CONSTRAINT_UNIQUE);
						break;
					default:
						throw new Exception('Could not save ' .
								    get_class($this) .
								    ' record. Reason: ' .
								    $e->getMessage());
						break;
				}
			}
		}
		else
		{
			throw new Exception('Validation error in "' .
					    get_class($this) . '".');
		}
	}

	public function _validates()
	{
		$res = true;
		foreach($this->fields as $fieldName => $description)
		{
			$notblank = false;
			if(isset($description['notblank']))
			{
				$notblank = (bool)$description['notblank'];
			}
			if($notblank and empty($this->fields[$fieldName]['value']))
			{
				$res = false;
				$this->errors[$fieldName][] = 'notblank';
			}
			if(($notblank or !empty($this->fields[$fieldName]['value']))
			    and !empty($description['validators']))
			{
				$value = null;
				if(isset($this->fields[$fieldName]['value']))
				{
					$value = $this->fields[$fieldName]['value'];
				}
				foreach($description['validators'] as $validator)
				{
					if(!$this->{$validator.'Validator'}($value))
					{
						$res = false;
						$this->errors[$fieldName][] = $validator;
					}
				}
			}
		}
		if(method_exists($this, 'validates') and $res === true)
		{
			return $this->validates();
		}
		return $res;
	}

	private function insert()
	{
		/*try
		{
			self::dbh()->getAdapter()->beginTransaction();*/
			self::dbh()->insert(get_class($this), $this->valuesArray());
			$this->fields['id']['value'] = self::dbh()->lastInsertId();
			//self::dbh()->getAdapter()->commit();
			return true;
		//}
		//catch(Exception $e)
		//{
		//	self::dbh()->getAdapter()->rollBack();
		//	return false;
		//}
	}

	private function update()
	{
		self::dbh()->update(get_class($this), $this->valuesArray(),
				'id=' . (int)$this->fields['id']['value']);
	}

	public static function dbh()
	{
		return mcz_DB::getInstance();
	}

	private function valuesArray()
	{
		$a = array();
		foreach($this->fields as $key => $value)
		{
			if($key != 'id' and isset($value['value']))
			{
				$a[$key] = $value['value'];
			}
		}
		return $a;
	}

	public function getTableSql()
	{
		$fields = array();
		foreach($this->fields as $fieldName => $description)
		{
			if($fieldName == 'id')
			{
				$fields[] = 'id integer primary key';
			}
			elseif(isset($description['unique'])
			       and $description['unique'] == true)
			{
				$fields[] = $fieldName . ' unique';
			}
			else
			{
				$fields[] = $fieldName;
			}
		}
		return 'create table ' . get_class($this) . '(' .
				implode(', ', $fields) . ');';
	}

	protected function lowercaseModifier($string)
	{
		return strtolower($string);
	}

	protected function uppercaseModifier($string)
	{
		return strtoupper($string);
	}

	protected function trimModifier($string)
	{
		return trim($string);
	}

	protected function nodiacriticsModifier($utfString)
	{
		return strtr(utf8_decode($utfString),
                     utf8_decode(
                      'ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ'),
                      'AAAAAAaaaaaaOOOOOOooooooEEEEeeeeCcIIIIiiiiUUUUuuuuyNn');
	}

	protected function emailValidator($string)
	{
		if(filter_var($string, FILTER_VALIDATE_EMAIL))
		{
			return true;
		}
		return false;
	}

	public function getErrors()
	{
		return $this->errors;
	}

	public static function hydrate($class, array $rows)
	{
		$objects = array();
        foreach($rows as $row)
        {
            $objects[] = new $class($row);
        }
        return $objects;
	}
}